import Cesium, { AssociativeArray } from '../Ces/Cesium';

interface DrawObject {
    id?: string;
    destroy(): void;
    update(frameState: any): void;
    [key: string]: any;
}

class GeometryManager {
    private _objs: AssociativeArray;
    private _isClearing: boolean = false;

    constructor() {
        this._objs = new Cesium.AssociativeArray();
    }

    add(drawObject: DrawObject): DrawObject {
        if (!Cesium.defined(drawObject)) {
            throw new Cesium.DeveloperError('drawObject is required.');
        }

        if (!Cesium.defined(drawObject.id)) {
            drawObject.id = Cesium.createGuid();
        }

        const id = drawObject.id;
        const objs = this._objs;

        if (objs.contains(id)) {
            throw new Cesium.RuntimeError(
                'An obj with id ' + id + ' already exists in this collection.',
            );
        }

        objs.set(id, drawObject);

        return drawObject;
    }

    remove(drawObject: DrawObject | string): boolean {
        if (!Cesium.defined(drawObject)) {
            return false;
        }

        if (typeof drawObject === 'string') {
            return this.removeById(drawObject);
        }

        if (!Cesium.defined(drawObject.id)) {
            return false;
        }

        if (!this._objs.remove(drawObject.id)) {
            return false;
        }

        drawObject.destroy();

        return true;
    }

    removeById(id: string): boolean {
        if (!Cesium.defined(id)) {
            return false;
        }

        const obj = this.getById(id);

        if (!Cesium.defined(obj)) {
            return false;
        }

        if (!this._objs.remove(id)) {
            return false;
        }

        obj.destroy();

        return true;
    }

    getById(id: string): DrawObject | undefined {
        if (!Cesium.defined(id)) {
            throw new Cesium.DeveloperError('id is required.');
        }

        return this._objs.get(id);
    }

    removeAll(): void {
        this._isClearing = true;
        const objs = this._objs;

        for (let i = 0; i < objs.length; i++) {
            const existingItem = objs.values[i];

            existingItem.destroy();
        }

        objs.removeAll();
        this._isClearing = false;
    }

    destroy(): void {
        this.removeAll();
    }

    isDestroyed(): boolean {
        return false;
    }

    update(frameState: any): void {
        if (this._isClearing) {
            return;
        }
        const objs = this._objs.values;

        for (let i = 0; i < objs.length; i++) {
            const drawObject = objs[i];

            drawObject.update(frameState);
        }
    }
}

export default GeometryManager;
